package com.lcc.forum.demos.web.services.impl;

import com.lcc.forum.demos.web.common.AppResult;
import com.lcc.forum.demos.web.common.ResultCode;
import com.lcc.forum.demos.web.dao.UserMapper;
import com.lcc.forum.demos.web.exception.ApplicationException;
import com.lcc.forum.demos.web.model.User;
import com.lcc.forum.demos.web.services.IUserService;
import com.lcc.forum.demos.web.utils.MD5Util;
import com.lcc.forum.demos.web.utils.StringUtil;
import com.lcc.forum.demos.web.utils.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

/**
 *实现接口IUserService,完成新增用户
 */
@Service
@Slf4j
public class UserServiceImpl implements IUserService {
    @Resource//用@Resource注入
    private UserMapper userMapper;
    @Override
    public void createNormalUser(User user) {
        //1.非空校验
        if (user == null || StringUtil.isEmpty(user.getUsername())
        ||StringUtil.isEmpty(user.getNickname())
        ||StringUtil.isEmpty(user.getPassword())
        ||StringUtil.isEmpty(user.getSalt())){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常,统一抛ApplicationException这个自定义的异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //2.按用户名查询用户信息
        User existUser = userMapper.selectByUserName((user.getUsername()));
        //2.1判断用户是否存在
        if (existUser != null){
            //打印日志
            log.info(ResultCode.FAILED_USER_EXISTS.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
        }
        //3.新增普通用户流程
        //3.1设置默认值，有些字段有默认值,虽然用户传的时候没有传对应一些值，数据库会进行赋默认值，
        // 但是在后端我们还是写上比较好,实现尽量让数据库少做一些赋值操作，能用代码控制就用代码控制
        user.setGender((byte) 2);
        user.setArticleCount(0);
        user.setIsAdmin((byte) 0);
        user.setState((byte) 0);
        user.setDeleteState((byte) 0);
        //3.2当前日期
        Date date = new Date();
        user.setCreateTime(date);
        user.setUpdateTime(date);
        //3.3写入数据库
        //这里进行动态插入，返回的是一个整数，表示受影响的行数
        int row = userMapper.insertSelective(user);
        if(row != 1){
            //打印日志
            log.info(ResultCode.FAILED_CREATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
        }
        //新增成功，打印日志
        log.info("新增用户成功，username = " + user.getUsername() + ".");
    }

    /**
     * 实现接口方法selectByUserName
     * @param username 用户名
     * @return
     */
    @Override
    public User selectByUserName(String username) {
        //非空校验
        if (StringUtil.isEmpty(username)){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //返回查询结果
        return userMapper.selectByUserName(username);
    }

    /**
     * 实现接口方法login
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @Override
    public User login(String username, String password) {
        //1非空校验
        if (StringUtil.isEmpty(username) || StringUtil.isEmpty(password)){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        //2按照用户名查询用户信息
        User user = userMapper.selectByUserName(username);
        //3对查询结果做非空校验
        if (user == null){
            //打印日志
            log.warn(ResultCode.FAILED_LOGIN.toString() + "username = " + username);
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        //4密码的密文与数据库里面的密码进行校验
        //4.1对密码的校验：用户传入的password是一个明文密码，需要与数据库该用户的盐进行计算生成一个MD5的密文，将这个密文与数据库中该用户的密文进行对比
        String encryptPassword = MD5Util.md5Salt(password, user.getSalt());
        if (!encryptPassword.equalsIgnoreCase(user.getPassword())) {//忽略大小写的相等校验
            //打印日志
            log.warn(ResultCode.FAILED_LOGIN.toString() + "密码错误，username = " + username);
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        //用户名找到了，且密码正确，则返回该用户
        //打印登陆成功的日志
        log.info("登录成功，username = " + username);
        return user;
    }
    /**
     *实现接口方法selectById
     * @param id 用户id
     * @return User对象
     */
    @Override
    public User selectById(Long id) {
        //1.非空校验
        if (id == null){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //2.调用DAO查询数据库并获取对象
        User user = userMapper.selectByPrimaryKey(id);
        //3.返回结果，如果为空到前端去校验
        return user;
    }
    //用户的发帖数 + 1
    @Override
    public void addOneArticleCountById(Long id) {
        //校验参数的有效性
        if (id == null || id <= 0){
            //打印日志
            log.warn(ResultCode.FAILED_BOARD_ARTICLE_COUNT.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_BOARD_ARTICLE_COUNT));
        }
        //参数有效，查询对应的用户对象
        User user = userMapper.selectByPrimaryKey(id);
        //校验对象的有效性
        if (user == null){
            //打印日志
            log.warn(ResultCode.ERROR_IS_NULL.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_IS_NULL));
        }
        //查询到对应对象，对对象的发帖数进行更新
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setArticleCount(user.getArticleCount() + 1);
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        //校验是否操作成功
        if(row != 1){
            //打印日志
            log.warn(ResultCode.FAILED.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
    }

    //用户的发帖数 - 1
    @Override
    public void subOneArticleCountById(Long id) {
        //校验参数的有效性
        if (id == null || id <= 0){
            //打印日志
            log.warn(ResultCode.FAILED_BOARD_ARTICLE_COUNT.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_BOARD_ARTICLE_COUNT));
        }
        //参数有效，查询对应的用户对象
        User user = userMapper.selectByPrimaryKey(id);
        //校验对象的有效性
        if (user == null){
            //打印日志
            log.warn(ResultCode.ERROR_IS_NULL.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_IS_NULL));
        }
        //查询到对应对象，对对象的发帖数进行更新
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setArticleCount(user.getArticleCount() - 1);
        if (updateUser.getArticleCount() < 0){
            updateUser.setArticleCount(0);
        }
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        //校验是否操作成功
        if(row != 1){
            //打印日志
            log.warn(ResultCode.FAILED.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
    }

    @Override
    public void modifyInfo(User user) {
        //进行参数校验
        if (user == null || user.getId() == null || user.getId() <= 0){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //校验传入的对象是否是存在的对象
        User existUser = userMapper.selectByPrimaryKey(user.getId());
        if (existUser == null || existUser.getDeleteState() == 1){
            //打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        //定义一个标志位
        boolean checkAttr = false;//false表示没有校验通过，设置的目的在于如果没有用户信息进行修改，修改用户信息就会失败
        //构建更新对象,之所以没有使用传进来的User对象，而是定义了一个专门用来更新的对象，
        // 是为了防止用户传入的User对象设置了其他多余的属性（因为这里只是允许修改用户的部分信息），
        // 当使用动态SQL进行更新的时候，覆盖了数据库中原本的字段
        User updateUser = new User();
        //设置对象的Id
        updateUser.setId(user.getId());
        //对每个参数进行校验并赋值
        //校验用户名
        //当更新的用户名不为空同时和原本的用户名不相等时进行更新，同时需要注意用户名具有唯一性，需要进行唯一性校验
        if (!StringUtil.isEmpty(user.getUsername()) &&
                !user.getUsername().equals(existUser.getUsername())){
            //进行用户名唯一性校验，看修改的用户名是否在数据库中已经存在
            User checkUser = userMapper.selectByUserName(user.getUsername());
            if (checkUser != null){
                //已存在该用户名，抛出异常
                log.warn(ResultCode.FAILED_USER_EXISTS.toString());
                //抛出异常
                throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
            }
            //进行用户名更新
            updateUser.setUsername(user.getUsername());
            //更新标志位，标志位设置为true
            checkAttr = true;
        }
        //校验昵称
        if (!StringUtil.isEmpty(user.getNickname()) &&
                !user.getNickname().equals(existUser.getNickname())){
            //更新昵称
            updateUser.setNickname(user.getNickname());
            //更新标志位
            checkAttr = true;
        }
        //校验性别
        if (user.getGender() != null &&
                user.getGender() != existUser.getGender()){
            //更新性别
            updateUser.setGender(user.getGender());
            //性别属性合法化
            if (updateUser.getGender() >  2 || updateUser.getGender() < 0){
                updateUser.setGender((byte) 2);
            }
            //更新标志位
            checkAttr = true;
        }
        //校验邮箱
        if (!StringUtil.isEmpty(user.getEmail()) &&
                !user.getEmail().equals(existUser.getEmail())){
            //更新昵称
            updateUser.setEmail(user.getEmail());
            //更新标志位
            checkAttr = true;
        }
        //校验电话号码
        if (!StringUtil.isEmpty(user.getPhoneNum()) &&
                !user.getPhoneNum().equals(existUser.getPhoneNum())){
            //更新昵称
            updateUser.setPhoneNum(user.getPhoneNum());
            //更新标志位
            checkAttr = true;
        }
        //校验个人介绍
        if (!StringUtil.isEmpty(user.getRemark()) &&
                !user.getRemark().equals(existUser.getRemark())){
            //更新昵称
            updateUser.setRemark(user.getRemark());
            //更新标志位
            checkAttr = true;
        }
        //校验标志位
        if (checkAttr == false){
            //此时表示没有进行任何的修改
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //调用DAO，更新用户信息
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        //校验操作是否成功
        if (row != 1){
            //打印日志
            log.warn(ResultCode.FAILED.toString() + "更新影响行数不为1");
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
    }


    @Override
    public void modifyPassword(Long id, String newPassword, String oldPassword) {
        //参数非空校验
        if(id == null || id <= 0 || StringUtil.isEmpty(newPassword) || StringUtil.isEmpty(oldPassword)){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //校验用户
        User user = userMapper.selectByPrimaryKey(id);
        if (user == null || user.getDeleteState() == 1){
            //打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        //校验输入的老密码和数据库中的密码是否一致
        String oldSalt = user.getSalt();
        String oldEncryPassword = MD5Util.md5Salt(oldPassword,oldSalt);
        if (!oldEncryPassword.equalsIgnoreCase(user.getPassword())){
            //打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            //抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        //对新密码进行加密
        String salt = UUIDUtil.UUID_32();
        String encryPassword = MD5Util.md5Salt(newPassword,salt);
        //构造更新的对象
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setSalt(salt);
        updateUser.setPassword(encryPassword);
        Date date = new Date();
        updateUser.setUpdateTime(date);
        //调用DAO，更新用户表
        userMapper.updateByPrimaryKeySelective(updateUser);
    }
}
